﻿using System;
using System.Linq;
using Domain;
using System.Collections;
using System.Collections.Generic;

namespace Presentation
{
    public class PresenterMessage
    {
        public const string StringIsNotSet = "Enter character string";
        public const string CodeIsNotSet = "Enter code";
        public const string CharactersIsWrong = "Character sequence is wrong";
        public const string SuccesAction= "The action is complete successfully";
        public const string FirstBuildTree = "Build tree first";
    }
    public class Presenter
    {
        private IView view;
        private ILogger log;
        private HuffmanCoding HCode= new HuffmanCoding();

        public Presenter(IView view, ILogger log)
        {
            if (view == null || log == null)
            {
                throw new ArgumentNullException();
            }

            this.log = log;

            this.view = view;
            this.view.CharacterString = "";
            this.view.HuffmanCode = "";
            this.view.Status = "";
            this.view.CharToCode = "";
            this.view.CodeToChar = "";
            setActions();
        }

        private void setActions()
        {
            view.OnEncode += OnEncode;
            view.OnDecode += OnDecode;
            view.OnStringChanged += onStringChanged;
            view.OnCodeChanged += onCodeChanged;
            view.OnBuildTree += onBuildTree;
        }

        public void setView(IView newView)
        {
            view = newView;
            setActions();
        }

        public void setLogger(ILogger logger)
        {
            view.Log = "";
            log = logger;
        }

        private string BitArrayToString(BitArray BA)
        {
            string str = "";
            foreach (bool bit in BA)
            {
                str = str + (bit ? 1 : 0);
            }
            return str;
        }

        private void OnEncode()
        {
            if (!HCode.Line.Equals(""))
            {
                if (view.CharacterString.Equals(""))
                {
                    view.HuffmanCode = "";
                    view.Status = PresenterMessage.StringIsNotSet;
                }
                else
                {
                    BitArray ArrayEncode = HCode.Encode(view.CharacterString);
                    if (ArrayEncode == null)
                    {
                        view.HuffmanCode = "";
                        view.Status = PresenterMessage.CharactersIsWrong;
                    }
                    else
                    {
                        view.HuffmanCode = BitArrayToString(ArrayEncode);
                        log.Write("Input string = " + view.CharacterString + " encoded.");
                        view.Log = log.Read();
                        view.Status = PresenterMessage.SuccesAction;
                    }                 
                }
            }
            else view.Status = PresenterMessage.FirstBuildTree;
        }

        private BitArray StringToBitArray(string Str)
        {
            var Array = new bool[Str.Length];
            int i = 0;
            foreach (char ch in Str)
            {
                if (ch == '1') Array[i] = true;
                else Array[i] = false;
                i++;
            }
            BitArray bits = new BitArray(Array);
            return bits;
        }

        private void OnDecode()
        {
            if (!HCode.Line.Equals(""))
            {
                foreach (char ch in view.HuffmanCode)
                    if (ch != '0' && ch != '1' && ch != '\b')
                        view.Status = PresenterMessage.CharactersIsWrong;

                if (view.HuffmanCode.Equals(""))
                {
                    view.CharacterString = "";
                    view.Status = PresenterMessage.CodeIsNotSet;
                }
                else if (!view.Status.Equals(PresenterMessage.CharactersIsWrong))
                {
                    string decoded = HCode.Decode(StringToBitArray(view.HuffmanCode));
                    view.CharacterString = decoded;
                    if (decoded == null)
                    {
                        view.CharacterString = "";
                        view.Status = PresenterMessage.CharactersIsWrong;
                    }
                    else
                    {
                        log.Write("Code = " + view.HuffmanCode + " decoded");
                        view.Log = log.Read();
                        view.Status = PresenterMessage.SuccesAction;
                    }                   
                }
            }
            else view.Status = PresenterMessage.FirstBuildTree;
        }
        private void onStringChanged()
        {
            view.Status = "";
        }
        private void onCodeChanged()
        {
            view.Status = "";
        }
        private void onBuildTree()
        {
            if (view.CharacterString.Equals(""))
            {
                view.HuffmanCode = "";
                view.Status = PresenterMessage.StringIsNotSet;
            }
            else
            {
                view.CharToCode = "";
                view.CodeToChar = "";
                HCode.BuildTree(view.CharacterString);
                view.HuffmanCode = BitArrayToString(HCode.Encode(view.CharacterString));
                Dictionary<char, BitArray> ListOfCode = HCode.CodeOfAlphabet();
                foreach (char ch in ListOfCode.Keys)
                {
                    string str1 = "" + ch;
                    string str2 = BitArrayToString(ListOfCode[ch]);

                    view.CharToCode = view.CharToCode + str1 + " - " + str2 + "\r\n";
                    view.CodeToChar = view.CodeToChar + str2 + " - " + str1 + "\r\n";
                }
                log.Write("New tree with input string = " + view.CharacterString + " was build. This string encoded.");
                view.Log = log.Read();
                view.Status = PresenterMessage.SuccesAction;
            }
        }
    }
   
}
